/* OpenPGP radix-64/base64 string encoding/decoding
 * Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
 * version 1.0, check www.haneWIN.de for the latest version

 * This software is provided as-is, without express or implied warranty.
 * Permission to use, copy, modify, distribute or sell this software, with or
 * without fee, for any purpose and by any individual or organization, is hereby
 * granted, provided that the above copyright notice and this paragraph appear
 * in all copies. Distribution as a part of an application or binary must
 * include the above copyright notice in the documentation and/or other materials
 * provided with the application or distribution.
 */

var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

function s2r( t )
{
    var a, c, n;
    var r = '', l = 0, s = 0;
    var tl = t.length;

    for (n = 0; n < tl; n++)
    {
        c = t.charCodeAt(n);
        if (s == 0)
        {
            r += b64s.charAt((c >> 2) & 63);
            a = (c & 3) << 4;
        }
        else if (s == 1)
        {
            r += b64s.charAt((a | (c >> 4) & 15));
            a = (c & 15) << 2;
        }
        else if (s == 2)
        {
            r += b64s.charAt(a | ((c >> 6) & 3));
            l += 1;
            if ((l % 60) == 0) r += "\n";
            r += b64s.charAt(c & 63);
        }
        l += 1;
        if ((l % 60) == 0) r += "\n";

        s += 1;
        if (s == 3) s = 0;
    }
    if (s > 0)
    {
        r += b64s.charAt(a);
        l += 1;
        if ((l % 60) == 0) r += "\n";
        r += '=';
        l += 1;
    }
    if (s == 1)
    {
        if ((l % 60) == 0) r += "\n";
        r += '=';
    }

    return r;
}

function r2s( t )
{
    var c, n;
    var r = '', s = 0, a = 0;
    var tl = t.length;

    for (n = 0; n < tl; n++)
    {
        c = b64s.indexOf(t.charAt(n));
        if (c >= 0)
        {
            if (s) r += String.fromCharCode(a | (c >> (6 - s)) & 255);
            s = (s + 2) & 7;
            a = (c << s) & 255;
        }
    }
    return r;
}

function s2hex( s )
{
    var result = '';
    for (var i = 0; i < s.length; i++)
    {
        var c = s.charCodeAt(i);
        result += ((c < 16) ? "0" : "") + c.toString(16);
    }
    return result;
}

function hex2s( hex )
{
    var r = '';
    if (hex.length % 2)
        hex += '0';

    for (var i = 0; i < hex.length; i += 2)
        r += String.fromCharCode(parseInt(hex.slice(i, i + 2), 16));
    return r;
}

// -----------------------------------------------------------------
// conversion functions: num array <-> multi precision integer (mpi)
// mpi: 2 octets with length in bits + octets in big endian order

function mpi2b( s )
{
    var bn = 1, r = [0], rn = 0, sb = 256;
    var c, sn = s.length;
    if (sn < 2)
    {
        throw new Error('string too short, not a MPI');
    }

    var len = (sn - 2) * 8;
    var bits = s.charCodeAt(0) * 256 + s.charCodeAt(1);
    if (bits > len || bits < len - 8)
    {
        throw new Error('not a MPI, bits=' + bits + ",len=" + len);
    }

    for (var n = 0; n < len; n++)
    {
        if ((sb <<= 1) > 255)
        {
            sb = 1;
            c = s.charCodeAt(--sn);
        }
        if (bn > hanna_bm)
        {
            bn = 1;
            r[++rn] = 0;
        }
        if (c & sb) r[rn] |= bn;
        bn <<= 1;
    }
    return r;
}

function b2mpi( b )
{
    var bn = 1, bc = 0, r = [0], rb = 1, rn = 0;
    var bits = b.length * hanna_bs;
    var n, rr = '';

    for (n = 0; n < bits; n++)
    {
        if (b[bc] & bn) r[rn] |= rb;
        if ((rb <<= 1) > 255)
        {
            rb = 1;
            r[++rn] = 0;
        }
        if ((bn <<= 1) > hanna_bm)
        {
            bn = 1;
            bc++;
        }
    }

    while (rn && r[rn] == 0) rn--;

    bn = 256;
    for (bits = 8; bits > 0; bits--)
        if (r[rn] & (bn >>= 1))
            break;
    bits += rn * 8;

    rr += String.fromCharCode(bits / 256) + String.fromCharCode(bits % 256);
    if (bits)
        for (n = rn; n >= 0; n--)
            rr += String.fromCharCode(r[n]);
    return rr;
}
